package thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @since Oct 21, 2017
 */
public class Synchronized {

    private volatile int i = 0;

    public synchronized int getI() {
        return i;
    }

    public synchronized void plusI() {
        i++;
        System.out.println("one\t" + i);
        Thread.yield();
        i++;
        System.out.println("two\t" + i);
    }

    public class A implements Runnable {

        private final int id;

        public A(int id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return Thread.currentThread() + ":" + id;
        }

        @Override
        public void run() {
            System.out.println("A\t" + this);
        }

    }

    public class B implements Runnable {

        private final int id;

        public B(int id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return Thread.currentThread() + ":" + id;
        }

        @Override
        public void run() {
            System.out.println("B\t" + this);
            plusI();
        }

    }

    public void test() {
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            exec.execute(new A(i));
            exec.execute(new B(i));
        }
        exec.shutdown();
    }

    public static void main(String[] args) {
        Synchronized s = new Synchronized();
        s.test();
        //[output] without synchronized(one of the output):
        /**
         A	Thread[pool-1-thread-1,5,main]:0
         B	Thread[pool-1-thread-1,5,main]:0
         one	1
         A	Thread[pool-1-thread-2,5,main]:1
         B	Thread[pool-1-thread-2,5,main]:1
         one	2
         A	Thread[pool-1-thread-3,5,main]:2
         A	Thread[pool-1-thread-3,5,main]:3
         B	Thread[pool-1-thread-4,5,main]:2
         one	3
         A	Thread[pool-1-thread-5,5,main]:4
         B	Thread[pool-1-thread-5,5,main]:4
         one	4
         two	5
         two	6
         two	7
         two	8
         B	Thread[pool-1-thread-3,5,main]:3
         one	9
         two	10
         */
        //[output]: with synchronized(one of the output)
        /**
         A	Thread[pool-1-thread-1,5,main]:0
         B	Thread[pool-1-thread-2,5,main]:0
         one	1
         A	Thread[pool-1-thread-1,5,main]:1
         A	Thread[pool-1-thread-1,5,main]:2
         B	Thread[pool-1-thread-3,5,main]:1
         A	Thread[pool-1-thread-1,5,main]:3
         B	Thread[pool-1-thread-4,5,main]:2
         A	Thread[pool-1-thread-1,5,main]:4
         B	Thread[pool-1-thread-5,5,main]:3
         B	Thread[pool-1-thread-6,5,main]:4
         two	2
         one	3
         two	4
         one	5
         two	6
         one	7
         two	8
         one	9
         two	10
         */
    }
}
